/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License,Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.victor.lib.core;

import com.victor.lib.core.util.AnimatorListenerAdapter;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.ColorFilter;
import ohos.agp.utils.Rect;
import ohos.app.Context;

public abstract class LoadingRenderer {
    public static interface Callback {
        public void invalidate();
    }

    private static final long ANIMATION_DURATION = 1333;
    private static final float DEFAULT_SIZE = 56.0f;

    private final AnimatorValue.ValueUpdateListener mAnimatorUpdateListener
            = new AnimatorValue.ValueUpdateListener() {
        @Override
        public void onUpdate(AnimatorValue animatorValue, float v) {
            computeRender(v);
            invalidateSelf();
        }
    };

    protected final Rect mBounds = new Rect();

    private Callback mCallback;
    private AnimatorValue mRenderAnimator;

    protected long mDuration;

    protected float mWidth;
    protected float mHeight;

    protected Context mContext;

    public LoadingRenderer(Context context) {
        mContext = context;
        initParams(context);
        setupAnimators();
    }

    @Deprecated
    protected void draw(Canvas canvas, Rect bounds) {
    }

    protected void draw(Canvas canvas) {
        draw(canvas, mBounds);
    }

    protected abstract void computeRender(float renderProgress);

    protected abstract void setAlpha(int alpha);

    protected abstract void setColorFilter(ColorFilter cf);

    protected abstract void reset();

    protected void addRenderListener(AnimatorListenerAdapter listener) {
        mRenderAnimator.setLoopedListener(listener);
        mRenderAnimator.setStateChangedListener(listener);
    }

    void start() {
        reset();
        mRenderAnimator.setValueUpdateListener(mAnimatorUpdateListener);
        mRenderAnimator.setLoopedCount(AnimatorValue.INFINITE);
        mRenderAnimator.setDuration(mDuration);
        mRenderAnimator.start();
    }

    void stop() {
        // if I just call mRenderAnimator.end(),
        // it will always call the method onAnimationUpdate(ValueAnimator animation)
        // why ? if you know why please send email to me (dinus_developer@163.com)
        mRenderAnimator.setValueUpdateListener(null);

        mRenderAnimator.setLoopedCount(0);
        mRenderAnimator.setDuration(0);
        mRenderAnimator.stop();
    }

    boolean isRunning() {
        return mRenderAnimator.isRunning();
    }

    void setCallback(Callback callback) {
        this.mCallback = callback;
    }

    void setBounds(Rect bounds) {
        if (bounds != null) {
            mBounds.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
        }
    }

    private void initParams(Context context) {
        mWidth = DensityUtil.dip2px(context, DEFAULT_SIZE);
        mHeight = DensityUtil.dip2px(context, DEFAULT_SIZE);

        mDuration = ANIMATION_DURATION;
    }

    private void setupAnimators() {
        mRenderAnimator = new AnimatorValue();
        mRenderAnimator.setLoopedCount(AnimatorValue.INFINITE);
        mRenderAnimator.setDuration(mDuration);
        //fuck you! the default interpolator is AccelerateDecelerateInterpolator
        mRenderAnimator.setCurveType(AnimatorValue.CurveType.LINEAR);
        mRenderAnimator.setValueUpdateListener(mAnimatorUpdateListener);
    }

    private void invalidateSelf() {
        mCallback.invalidate();
    }

}
